
package uebung03;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;

import javax.swing.JComponent;
import javax.swing.JFrame;

import org.ejml.simple.SimpleMatrix;

import Jama.Matrix;

public class VanishingPoint {
	public static void main(String[] args) {
	//Garland Heckbert:
		
		final ArrayList<Point2D> as = new ArrayList<Point2D>(), bs = new ArrayList<Point2D>();
		as.add(new Point2D.Double(0,0));
		bs.add(new Point2D.Double(400, 400));

		as.add(new Point2D.Double(400,0));
		bs.add(new Point2D.Double(0,400));
		
		final Point2D free1 = new Point2D.Double(150,0), free2 = new Point2D.Double(150,400);
		
		as.add(free1);
		bs.add(free2);

		
		JFrame ff = new JFrame();
		ff.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		final JComponent canvas = new JComponent() {
			
			{setPreferredSize(new Dimension(300,300));}
			
			Line2D line = new Line2D.Double();
			Ellipse2D marker = new Ellipse2D.Double();
			
			public void paint(java.awt.Graphics g) {
			
				final ArrayList<Point2D> normals = new ArrayList<Point2D>();
				final ArrayList<Double> distances = new ArrayList<Double>();
				
				for (int i = 0; i<as.size(); i++) {
					
					Point2D a = as.get(i), b = bs.get(i), ba = new Point2D.Double(b.getX()-a.getX(), b.getY()-a.getY());
					double norml = Math.sqrt(ba.getX()*ba.getX()+ba.getY()*ba.getY());
					Point2D normal = new Point2D.Double(ba.getY()/norml, -ba.getX()/norml);
					normals.add(normal);
					distances.add(a.getX()*normal.getX()+a.getY()*normal.getY());
				}
				
				double xx = 0, yx = 0, yy = 0, tx = 0, ty = 0;
				
				for (int i = 0; i<normals.size(); i++) {
					Point2D norml = normals.get(i);
					double a1 = norml.getX(), a2 = norml.getY(), c = distances.get(i);
					xx += a1*a1;
					yx += a1*a2;
					yy += a2*a2;
					tx += a1*c;
					ty += a2*c;
				}
				
				Matrix sm = new Matrix(2, 2);
				
				sm.set(0, 0, xx);
				sm.set(0, 1, yx);
				sm.set(1, 0, yx);
				sm.set(1, 1, yy);
				
				Matrix avec = new Matrix(2, 1);
				avec.set(0, 0, tx);
				avec.set(1, 0, ty);
				
				Matrix vanish = sm.solve(avec);
				
				final Point2D vanishingPoint = new Point2D.Double(vanish.get(0,0), vanish.get(1,0));
				Graphics2D g2 = (Graphics2D)g;

				g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
				g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
				g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);

				g2.setColor(Color.black);
				for (int i = 0; i<as.size(); i++) {
					line.setLine(as.get(i), bs.get(i));
					g2.draw(line);
				}
				marker.setFrameFromCenter(vanishingPoint, new Point2D.Double(vanishingPoint.getX()-2, vanishingPoint.getY()-2));
				g2.setColor(Color.magenta);
				g2.fill(marker);
			};
		};
		canvas.addMouseMotionListener(new MouseMotionAdapter() {
			@Override
			public void mouseMoved(MouseEvent e) {
				free1.setLocation(e.getX(), 0);
				
				free2.setLocation(e.getX(), 400);
				canvas.repaint();
				super.mouseMoved(e);
			}
		});
		ff.add(canvas);
		ff.pack();
		ff.setVisible(true);
	}
	
}
